package com.roc.demo.proxy;

import cn.hutool.core.collection.CollUtil;
import com.roc.demo.RpcApplication;
import com.roc.demo.config.RpcConfig;
import com.roc.demo.constant.RpcConstant;
import com.roc.demo.fault.retry.RetryStrategy;
import com.roc.demo.fault.retry.RetryStrategyFactory;
import com.roc.demo.fault.tolerant.TolerantStrategy;
import com.roc.demo.fault.tolerant.TolerantStrategyFactory;
import com.roc.demo.loadbalancer.LoadBalancer;
import com.roc.demo.loadbalancer.LoadBalancerFactory;
import com.roc.demo.model.RpcRequest;
import com.roc.demo.model.RpcResponse;
import com.roc.demo.model.ServiceMetaInfo;
import com.roc.demo.registry.Registry;
import com.roc.demo.registry.RegistryFactory;
import com.roc.demo.service.tcp.VertxTcpClient;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 服务代理（jdk动态代理）
 */
public class ServiceProxy implements InvocationHandler {

    /**
     * 调用代理
     * 当用户调用某个接口的方法时，改为调用 invoke 方法。在该方法中，可以获取到要调用的方法信息、传入的参数列表等服务提供者需要的参数，
     * 用这些参数来构造请求对象就可以完成调用
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 构造请求
        String serviceName = method.getDeclaringClass().getName();
        RpcRequest rpcRequest = RpcRequest.builder()
                .serviceName(serviceName)
                .methodName(method.getName())
                .parameterTypes(method.getParameterTypes())
                .args(args)
                .build();

            // 从注册中心获取服务提供者请求地址
            RpcConfig rpcConfig = RpcApplication.getRpcConfig();
            Registry registry = RegistryFactory.getInstance(rpcConfig.getRegistryConfig().getRegistry());
            ServiceMetaInfo serviceMetaInfo = new ServiceMetaInfo();
            serviceMetaInfo.setServiceName(serviceName);
            serviceMetaInfo.setServiceVersion(RpcConstant.DEFAULT_SERVICE_VERSION);
            List<ServiceMetaInfo> serviceMetaInfoList = registry.serviceDiscovery(serviceMetaInfo.getServiceKey());
            if (CollUtil.isEmpty(serviceMetaInfoList)) {
                throw new RuntimeException("暂无服务地址");
            }
            // 暂时先取第一个 ——》 负载均衡
//            ServiceMetaInfo selectedServiceMetaInfo = serviceMetaInfoList.get(0);
            LoadBalancer loadBalancer = LoadBalancerFactory.getInstance(rpcConfig.getLoadBalancer());

            // 将调用方法名（请求路径）作为负载均衡参数
            Map<String, Object> requestParams = new HashMap<>();
            String methodName = rpcRequest.getMethodName();
            System.out.println("methodName:" + methodName);
            requestParams.put("methodName", methodName);
            ServiceMetaInfo selectedServiceMetaInfo = loadBalancer.select(requestParams, serviceMetaInfoList);

//        // 使用http协议发送请求 ——》 使用tcp协议发送请求
//        //这里删除了序列化器的指定和序列化的代码
//        try (HttpResponse httpResponse = HttpRequest.post(selectedServiceMetaInfo.getServiceAddress())
//                .body(bodyBytes)
//                .execute()) {
//            byte[] result = httpResponse.bodyBytes();
//            // 反序列化
//            RpcResponse rpcResponse = serializer.deserialize(result, RpcResponse.class);
//            return rpcResponse.getData();
//        }

            // 发送 TCP 请求
//            Vertx vertx = Vertx.vertx();
//            NetClient netClient = vertx.createNetClient();
//            CompletableFuture<RpcResponse> responseFuture = new CompletableFuture<>();
//            netClient.connect(selectedServiceMetaInfo.getServicePort(), selectedServiceMetaInfo.getServiceHost(),
//                    result -> {
//                        if (result.succeeded()) {
//                            System.out.println("Connected to TCP server");
//                            io.vertx.core.net.NetSocket socket = result.result();
//                            // 发送数据
//                            // 构造消息
//                            ProtocolMessage<RpcRequest> protocolMessage = new ProtocolMessage<>();
//                            ProtocolMessage.Header header = new ProtocolMessage.Header();
//                            header.setMagic(ProtocolConstant.PROTOCOL_MAGIC);
//                            header.setVersion(ProtocolConstant.PROTOCOL_VERSION);
//                            header.setSerializer((byte) ProtocolMessageSerializerEnum.getEnumByValue(RpcApplication.getRpcConfig().getSerializer()).getKey());
//                            header.setType((byte) ProtocolMessageTypeEnum.REQUEST.getKey());
//                            header.setRequestId(IdUtil.getSnowflakeNextId());
//                            protocolMessage.setHeader(header);
//                            protocolMessage.setBody(rpcRequest);
//                            // 编码请求
//                            try {
//                                Buffer encodeBuffer = ProtocolMessageEncoder.encode(protocolMessage);
//                                socket.write(encodeBuffer);
//                            } catch (IOException e) {
//                                throw new RuntimeException("协议消息编码错误");
//                            }
//
//                            // 接收响应
//                            socket.handler(buffer -> {
//                                try {
//                                    ProtocolMessage<RpcResponse> rpcResponseProtocolMessage = (ProtocolMessage<RpcResponse>) ProtocolMessageDecoder.decode(buffer);
//                                    responseFuture.complete(rpcResponseProtocolMessage.getBody());
//                                } catch (IOException e) {
//                                    throw new RuntimeException("协议消息解码错误");
//                                }
//                            });
//                        } else {
//                            System.err.println("Failed to connect to TCP server");
//                        }
//                    });
//
//            RpcResponse rpcResponse = responseFuture.get();
//            // 记得关闭连接
//            netClient.close();

            // tcp协议请求代码封装成方法
//            RpcResponse rpcResponse = VertxTcpClient.doRequest(rpcRequest, selectedServiceMetaInfo);

//            //使用重试机制
//            RetryStrategy retryStrategy = RetryStrategyFactory.getInstance(RpcApplication.getRpcConfig().getRetryStrategy());
//            RpcResponse rpcResponse = retryStrategy.doRetry(() ->
//                VertxTcpClient.doRequest(rpcRequest, selectedServiceMetaInfo)
//            );
//            return rpcResponse.getData();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }

        RpcResponse rpcResponse;
        try {
            RetryStrategy retryStrategy = RetryStrategyFactory.getInstance(rpcConfig.getRetryStrategy());
            rpcResponse = retryStrategy.doRetry(() ->
                    VertxTcpClient.doRequest(rpcRequest, selectedServiceMetaInfo)
            );
        } catch (Exception e) {
            // 容错机制
            TolerantStrategy tolerantStrategy = TolerantStrategyFactory.getInstance(rpcConfig.getTolerantStrategy());
            rpcResponse = tolerantStrategy.doTolerant(null, e);
        }
        return rpcResponse.getData();
    }
}

